﻿using AutoUpdaterDotNET;
using BarrageGameAssistant.Core.Configs;
using BarrageGameAssistant.Core.Engines;
using BarrageGameAssistant.Core.Utils;
using BarrageGameAssistant.UIForms;
using NLog;
using SharpHook;
using SharpHook.Reactive;
using WinCapturer;
using BarrageGameAssistant.Core.Extensions;
using BarrageGameAssistant.Core.Enums;
using BarrageGameAssistant.Core.Model;

namespace BarrageGameAssistant
{
    public partial class FrmMain : Form
    {
        #region 私有属性
        private readonly Logger _logger = LogManager.GetCurrentClassLogger();
        private readonly SynchronizationContext? _syncContext;
        private FrmMonitorShow? _monitorShow = null;

        private System.Timers.Timer _timer;
        private Settings _settings; //程序配置信息
        private Licence? _licence; //许可证
        private GameProject? _currentGame; //当前游戏

        private bool _isRunning; //否自动运行中
        private SimpleReactiveGlobalHook _hook;
        private bool _hookStartGame;

        private bool _reCapture;
        private CaptureHelper? _captureHelper;
        private Bitmap? _currentImage; //当前游戏画面

        private SceneMatchEngine _sceneMatchEngine; //场景处理引擎
        private ProcessMatchEngine _processMatchEngine; //过程数据处理引擎
        private LanguageScriptEngine _languageScriptEngine; //话术引擎
        private KMActionEngine _kmActionEngine; //键鼠动作引擎
        #endregion

        public FrmMain()
        {
            InitializeComponent();
            _hook = new SimpleReactiveGlobalHook();
            _hook.KeyPressed.Subscribe(OnHookEvent);
            _syncContext = SynchronizationContext.Current;
            _settings = Settings.Load();
            _timer = new System.Timers.Timer(1000);
            _timer.Elapsed += _timer_Elapsed;

            _sceneMatchEngine = new SceneMatchEngine(_settings);
            _processMatchEngine = new ProcessMatchEngine(_settings);
            _languageScriptEngine = new LanguageScriptEngine(_settings);
            _kmActionEngine = new KMActionEngine(_settings);
        }

        #region 内部方法
        /// <summary>
        /// 写日志
        /// </summary>
        /// <param name="message"></param>
        /// <param name="level"></param>
        protected void WriteLog(string message, Barrage.Controls.LogLevel level = Barrage.Controls.LogLevel.Info)
        {
            if (level != Barrage.Controls.LogLevel.Info)
            {
                _logger.Error(message);
            }

            Application.DoEvents();
            Invoke((new Action(() =>
            {
                lvLogs.SetLog(message, level);
            })));
        }

        private void _timer_Elapsed(object? sender, System.Timers.ElapsedEventArgs e)
        {
            try
            {
                Application.DoEvents();
                Invoke((new Action(() =>
                {
                    tsslCurrentTime.Text = "当前时间：" + DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss");
                })));

                if (_currentGame != null && _isRunning)
                {
                    if (_currentGame.GetGameHandle() == IntPtr.Zero && _reCapture == false)
                    {
                        _captureHelper?.Stop();
                        _captureHelper = null;
                        _reCapture = true;
                    }
                    else
                    {
                        if (_reCapture)
                        {
                            _reCapture = false;
                            if (_captureHelper != null) return;
                            _captureHelper = new CaptureHelper();
                            _captureHelper.Fps = _settings.CaptureFrameRate;
                            _captureHelper.CaptureDone += OnCaptureDone;
                            _captureHelper?.Start(Guid.NewGuid().ToString(), _currentGame.Handle, CaptureType.PrintWindow);
                        }
                    }
                }
            }
            catch (Exception)
            {

            }
        }

        private void SaveSetting()
        {
            _settings.Save();
            //_lsScriptEngine.RefreshSetting();

            //WriteLog("保存全局配置.");
        }

        private void LoadSetting()
        {
            //加载全局配置
            tsslCurrentTime.Text = "当前时间：" + DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss");
            tsslVersion.Text = $"版本：{VersionUtils.GetVersion()}";
            tsslNetInfo.Text = $"网络：{NetUtils.GetIp()}";

            #region 调试状态显示
            tsmiDebug.Checked = _settings.Debug;
            if (_settings.Debug)
            {
                tsslDebug.Text = "调试状态";
                tsslDebug.ForeColor = Color.Red;
            }
            else
                tsslDebug.Text = string.Empty;
            #endregion

            //分辨率显示
            this.cbbDefaultResolutionRatio.Text = this._settings.DefaultResolutionRatio;


            this.slvWelcomeScripts.SetData(_settings.WelcomeScripts);
            this.slvFansClubScripts.SetData(_settings.FansClubScripts);

            WriteLog("全局配置加载完成.");
        }

        /// <summary>
        /// 改变当前游戏配置
        /// </summary>
        /// <param name="currentGame"></param>
        private void ChangeCurrentGame(GameProject currentGame)
        {
            _currentGame = currentGame;
        }

        /// <summary>
        /// 保存当前游戏配置
        /// </summary>
        private void SaveCurrentGame()
        {
            if (_settings == null) return;
            if (_currentGame == null) return;

            var file = Path.Combine(_settings.GameDirectory, $"{_currentGame.GetPlatformName()}{_currentGame.Name}", "project.json");
            _currentGame.Save(file);
            //_lsScriptEngine.RefreshGame();
        }

        /// <summary>
        /// 刷新游戏相关的界面元素
        /// </summary>
        private void RefreshGameUI()
        {
            if (this._currentGame == null) return;
            //从当前游戏配置this._currentGame中刷新

            this.tslCurrentGame.Text = $"当前游戏: {this._currentGame.GetPlatformName()}{this._currentGame.Name}";
            this.tslCurrentGame.ForeColor = Color.Blue;

            foreach (var item in this._currentGame.ModeSelections)
            {
                this.tsccbModeSelection.Items.Add(item.Name);
            }
            this.tsccbModeSelection.SelectedIndex = 0;

            this.slvIntroScripts.SetData(this._currentGame.IntroScripts ?? ([]));
            this.slvInviteScripts.SetData(this._currentGame.InviteScripts ?? ([]));

            //this.lvGameProcessConditions.Items.Clear();
            //foreach (var item in this.CurrentGame.ProcessConditionsScripts ?? ([]))
            //{
            //    ListViewItem lst = this.lvGameProcessConditions.Items.Add((this.lvGameProcessConditions.Items.Count + 1).ToString());
            //    lst.Tag = item;
            //    lst.SubItems.Add(item.VariableName);
            //    lst.SubItems.Add(item.Logic.ToDesc());
            //    if (item.Logic == LogicType.WithIn)
            //    {
            //        lst.SubItems.Add($"({item.LeftValue},{item.RightValue})");
            //    }
            //    else
            //    {
            //        lst.SubItems.Add($"{item.LeftValue}");
            //    }
            //}

            this.cbbDefaultResolutionRatio.Enabled = true;
            this.tsbtnStart.Enabled = true;

            //填充场景列表
            FillSceneListView(_settings.DefaultResolutionRatioSize);
        }

        //填充场景ListView
        private void FillSceneListView(Size resolutionRatio)
        {
            if (_currentGame != null)
            {
                this.sceneView.Items.Clear();
                foreach (var item in _currentGame.Scenes.Where(x => x.SceneResolutionRatio == resolutionRatio).OrderBy(x => x.Index))
                {
                    ListViewItem lvi = this.sceneView.Items.Add(item.Index.ToString());
                    lvi.Tag = item;
                    lvi.SubItems.Add(item.Name);
                    lvi.SubItems.Add(item.SceneType.ToDesc());
                    lvi.SubItems.Add(item.Threshold.ToString("F2"));
                    lvi.SubItems.Add(item.StopDuration.ToString());
                    lvi.SubItems.Add(item.ToString());
                }
            }
        }
        #endregion

        #region 程序加载、关闭处理
        private void FrmMain_Load(object sender, EventArgs e)
        {
            LoadSetting();
            _timer.Start();
        }

        private void FrmMain_Shown(object sender, EventArgs e)
        {
            FrmLicence frmLicence = new()
            {
                Settings = _settings
            };
            if (frmLicence.ShowDialog() == DialogResult.OK)
            {
                this._licence = frmLicence.LicInfo;
                SaveSetting();

                this.lbLicInfo.Text = $"授权成功，卡密到期时间：{this._licence?.ExpTime?.ToString("yyyy-MM-dd HH:mm:ss")}";

                AutoUpdater.AppTitle = "弹幕游戏助手";
                AutoUpdater.SetOwner(this);
                AutoUpdater.TopMost = true;
                //AutoUpdater.ClearAppDirectory = true;
                AutoUpdater.ApplicationExitEvent += AutoUpdater_ApplicationExitEvent;
                AutoUpdater.ExecutablePath = "BarrageGameHangup.exe";
                AutoUpdater.Start("http://82.157.254.209/bgh/update.xml");

                if (_settings.AutoLoadGame)
                {
                    try
                    {
                        string gamePrj = Path.Combine(_settings.GameDirectory, _settings.DefaultGame, "project.json");

                        var game = GameProject.Load(gamePrj);
                        if (game != null)
                        {
                            this.ChangeCurrentGame(game);
                            RefreshGameUI();

                            WriteLog($"自动载入游戏: [{this._currentGame?.GetPlatformName()}{this._currentGame?.Name}] 的配置.");
                        }
                    }
                    catch (Exception)
                    {
                        WriteLog($"自动自动载入游戏配置失败.", Barrage.Controls.LogLevel.Error);
                    }
                }

                //hook.RunAsync();
            }
            else
            {
                Application.Exit();
            }
        }

        private void AutoUpdater_ApplicationExitEvent()
        {
            Text = @"即将关闭当前控制器";
            Thread.Sleep(3000);
            Application.Exit();
        }

        private void FrmMain_FormClosing(object sender, FormClosingEventArgs e)
        {
            _timer.Stop();

            _captureHelper?.Stop();
            _captureHelper = null;

            _sceneMatchEngine.Stop();
            _processMatchEngine.Stop();
            _kmActionEngine.Stop();
            _languageScriptEngine.Stop();

            _isRunning = false;
        }

        private void FrmMain_FormClosed(object sender, FormClosedEventArgs e)
        {
            _timer.Dispose();
        }

        private void cbbDefaultResolutionRatio_SelectedIndexChanged(object sender, EventArgs e)
        {
            if (this._settings.DefaultResolutionRatio != this.cbbDefaultResolutionRatio.Text)
            {
                string[] tmp = this.cbbDefaultResolutionRatio.Text.Split("x");
                this._settings.DefaultResolutionRatio = this.cbbDefaultResolutionRatio.Text;
                this._settings.DefaultResolutionRatioSize = new Size(Convert.ToInt32(tmp[0]), Convert.ToInt32(tmp[1]));
                SaveSetting();
            }
        }
        #endregion

        #region 顶部菜单处理事件
        #region 文件菜单
        private void tsmiCreateGameConfig_Click(object sender, EventArgs e)
        {
            if (_licence?.UseCreate == 0)
            {
                MessageBox.Show(this, $"没有该权限,请升级卡密.", "错误提示", MessageBoxButtons.OK, MessageBoxIcon.Error);
                return;
            }

            if (_settings == null) return;

            FrmCreateGameConfig frmCreateGameConfig = new()
            {
                Settings = _settings
            };
            if (frmCreateGameConfig.ShowDialog() == DialogResult.OK)
            {
                if (frmCreateGameConfig.Project == null) return;
                //初始化项目，并保存项目
                frmCreateGameConfig.Project.InitGameProject(_settings.GameDirectory);

                if (MessageBox.Show(this, $"是否加载游戏?", "信息确认", MessageBoxButtons.OKCancel, MessageBoxIcon.Question) == DialogResult.OK)
                {
                    this.ChangeCurrentGame(frmCreateGameConfig.Project);
                    _settings.DefaultGame = $"{frmCreateGameConfig.Project.GetPlatformName()}{frmCreateGameConfig.Project.Name}";
                    SaveSetting();
                    RefreshGameUI();

                    WriteLog($"载入游戏: [{this._currentGame?.GetPlatformName()}{this._currentGame?.Name}] 的配置.");
                }
            }
        }

        private void tsmiEditGameConfig_Click(object sender, EventArgs e)
        {
            if (_settings == null) return;
            if (_currentGame == null) return;

            FrmCreateGameConfig frmCreateGameConfig = new()
            {
                Settings = _settings,
                Project = _currentGame
            };
            if (frmCreateGameConfig.ShowDialog() == DialogResult.OK)
            {
                if (frmCreateGameConfig.Project == null) return;
                this.ChangeCurrentGame(frmCreateGameConfig.Project);
                SaveCurrentGame();
            }
        }

        private void tsmiOpenGameConfig_Click(object sender, EventArgs e)
        {
            if (_settings == null) return;

            FrmOpenGame frmOpenGame = new()
            {
                Settings = _settings
            };
            if (frmOpenGame.ShowDialog() == DialogResult.OK)
            {
                if (frmOpenGame.Project == null) return;
                this.ChangeCurrentGame(frmOpenGame.Project);
                _settings.DefaultGame = $"{frmOpenGame.Project.GetPlatformName()}{frmOpenGame.Project.Name}";
                SaveSetting();
                RefreshGameUI();

                WriteLog($"载入游戏: [{this._currentGame?.GetPlatformName()}{this._currentGame?.Name}] 的配置.");
            }
        }

        private void tsmiSaveGameConfig_Click(object sender, EventArgs e)
        {
            SaveSetting();
        }

        private void tsmiExit_Click(object sender, EventArgs e)
        {
            this.Close();
        }
        #endregion

        #region 设置菜单下按钮事件
        private void tsmiGlobalSetting_Click(object sender, EventArgs e)
        {
            if (_settings == null) return;

            FrmGlobalSetting frmGlobalSetting = new()
            {
                Settings = _settings
            };
            if (frmGlobalSetting.ShowDialog() == DialogResult.OK)
            {
                SaveSetting();
            }
        }

        private void tsmiCurrentGameSetting_Click(object sender, EventArgs e)
        {
            if (_currentGame == null)
            {
                MessageBox.Show(this, $"请先加载游戏.", "错误提示", MessageBoxButtons.OK, MessageBoxIcon.Error);
                return;
            }

            FrmGameSetting frmGameSetting = new()
            {
                CurrentGame = _currentGame
            };

            if (frmGameSetting.ShowDialog() == DialogResult.OK)
            {
                SaveCurrentGame();
                RefreshGameUI();
            }
        }
        #endregion

        #region 工具菜单按钮
        private void tsmiDebug_Click(object sender, EventArgs e)
        {
            if (_settings == null) return;
            _settings.Debug = !tsmiDebug.Checked;
            tsmiDebug.Checked = _settings.Debug;
            if (_settings.Debug)
            {
                tsslDebug.Text = "调试状态";
                tsslDebug.ForeColor = Color.Red;
            }
            else
                tsslDebug.Text = string.Empty;
            SaveSetting();
        }

        private void tsmiOpenGameConfigDir_Click(object sender, EventArgs e)
        {
            System.Diagnostics.Process.Start("explorer.exe", _settings.GameDirectory);
        }

        private void tsmiTestScriptChannel_Click(object sender, EventArgs e)
        {

        }
        #endregion

        #region 帮助菜单
        private void tsmiHelpDoc_Click(object sender, EventArgs e)
        {

        }

        private void tsmiAbout_Click(object sender, EventArgs e)
        {

        }
        #endregion
        #endregion



        #region 基础话术
        private void slvWelcomeScripts_DataChanged(object sender, EventArgs e)
        {
            //保存全局欢迎话术
            _settings.WelcomeScripts = slvWelcomeScripts.GetData();
            SaveSetting();
        }

        private void slvFansClubScripts_DataChanged(object sender, EventArgs e)
        {
            //保存拉灯牌、关注话术
            _settings.FansClubScripts = slvFansClubScripts.GetData();
            SaveSetting();
        }

        private void slvIntroScripts_DataChanged(object sender, EventArgs e)
        {
            //保存游戏介绍话术
            if (_currentGame == null) return;
            this._currentGame.IntroScripts = slvIntroScripts.GetData();
            SaveCurrentGame();
        }

        private void slvInviteScripts_DataChanged(object sender, EventArgs e)
        {
            //保存邀请落座话术
            if (_currentGame == null) return;
            this._currentGame.InviteScripts = slvInviteScripts.GetData();
            SaveCurrentGame();
        }
        #endregion

        private void tsmiCreateScene_Click(object sender, EventArgs e)
        {
            if (_licence?.UseEdit == 0)
            {
                MessageBox.Show(this, $"没有该权限,请升级卡密.", "错误提示", MessageBoxButtons.OK, MessageBoxIcon.Error);
                return;
            }

            if (_settings == null) return;
            if (_currentGame == null) return;

            FrmSceneEditor frmSceneEditor = new()
            {
                Licence = _licence,
                Settings = _settings,
                CurrentGame = _currentGame,
                Scene = null
            };

            if (frmSceneEditor.ShowDialog() == DialogResult.OK)
            {
                if (frmSceneEditor.Scene == null) return;

                _currentGame.Scenes.Add(frmSceneEditor.Scene);

                SaveCurrentGame();

                ListViewItem lvi = sceneView.Items.Add((sceneView.Items.Count + 1).ToString());
                lvi.Tag = frmSceneEditor.Scene;
                lvi.SubItems.Add(frmSceneEditor.Scene.Name);
                lvi.SubItems.Add(frmSceneEditor.Scene.SceneType.ToDesc());
                lvi.SubItems.Add(frmSceneEditor.Scene.Threshold.ToString("F2"));
                lvi.SubItems.Add(frmSceneEditor.Scene.StopDuration.ToString());
                lvi.Focused = true;

                string logText = $"新建场景:{frmSceneEditor.Scene.Name}, {frmSceneEditor.Scene}";
                WriteLog(logText);
            }

        }

        private void tsmiEditScene_Click(object sender, EventArgs e)
        {
            if (_settings == null) return;
            if (_currentGame == null) return;

            if (this.sceneView.SelectedItems.Count == 0) return;
            ListViewItem lvi = this.sceneView.SelectedItems[0];
            if (lvi == null) return;
            if (lvi.Tag is not Scene scene) return;

            FrmSceneEditor frmSceneEditor = new()
            {
                Licence = _licence,
                Settings = _settings,
                CurrentGame = _currentGame,
                Scene = scene
            };
            if (frmSceneEditor.ShowDialog() == DialogResult.OK)
            {
                if (frmSceneEditor.Scene == null) return;

                lvi.Tag = frmSceneEditor.Scene;
                lvi.SubItems[1].Text = frmSceneEditor.Scene.Name;
                lvi.SubItems[2].Text = frmSceneEditor.Scene.SceneType.ToDesc();
                lvi.SubItems[4].Text = frmSceneEditor.Scene.Threshold.ToString("F2");
                lvi.SubItems[3].Text = frmSceneEditor.Scene.StopDuration.ToString();
                
                SaveCurrentGame();

                string logText = $"编辑场景:{scene.Name}, {frmSceneEditor.Scene}";
                WriteLog(logText);
            }
        }

        private void tsmiDeleteScene_Click(object sender, EventArgs e)
        {

        }

        private void tsccbModeSelection_SelectedIndexChanged(object sender, EventArgs e)
        {
            if (this._currentGame == null) return;

            var name = tsccbModeSelection.Text;
            var mst = this._currentGame.ModeSelections.FirstOrDefault(x => x.Name == name);
            if (mst != null)
            {
                this._currentGame.DefaultModeSelectionId = mst.Id;
                SaveCurrentGame();
            }
        }



        #region 画面采集、监视器显示
        private void MonitorShow(IntPtr bitmapPtr)
        {
            if (_currentGame == null) return;

            try
            {
                if (_settings.IsMonitorOpen && _monitorShow != null)
                {
#pragma warning disable CS8604 // 引用类型参数可能为 null。
                    _monitorShow.SetImage(_currentGame.GetImage(_currentGame.Capture()));
#pragma warning restore CS8604 // 引用类型参数可能为 null。
                }
            }
            catch (Exception)
            {

            }
        }

        private void OnCaptureDone(string captureName, IntPtr bitmapPtr, Win32Proxy.Structs.BitmapInfo bitmapInfo)
        {
            try
            {
                MonitorShow(bitmapPtr);
                _sceneMatchEngine.SetCurrentImage(bitmapPtr);
                _processMatchEngine.SetCurrentImage(bitmapPtr);
            }
            catch (Exception e)
            {
                WriteLog(e.Message, Barrage.Controls.LogLevel.Error);
            }
        }

        private void tsBtnMonitorOpen_Click(object sender, EventArgs e)
        {
            if (_settings == null) return;
            if (_currentGame == null) return;

            if (_settings.IsMonitorOpen == false)
            {
                _monitorShow?.Dispose();
                _monitorShow = null;
                _monitorShow = new FrmMonitorShow();
                _monitorShow.Settings = _settings;
                _monitorShow.Show(this);
            }
        }
        #endregion

        private void tsbtnStart_Click(object sender, EventArgs e)
        {
            if (_settings == null || _currentGame == null)
            {
                MessageBox.Show(this, $"游戏配置未加载,请先加载游戏.", "错误提示", MessageBoxButtons.OK, MessageBoxIcon.Error);
                return;
            }

            if (!_currentGame.IsRunning())
            {
                MessageBox.Show(this, $"游戏没启动,请启动游戏: {_currentGame.GetPlatformName()}{_currentGame.Name}", "提示", MessageBoxButtons.OK, MessageBoxIcon.Warning);
                return;
            }

            if (_isRunning)
            {
                if (_hookStartGame == false)
                {
                    if (MessageBox.Show(this, $"是否停止游戏自动运行.", "提示", MessageBoxButtons.OKCancel, MessageBoxIcon.Question) == DialogResult.OK)
                    {
                        Stop();
                    }
                }
                else
                {
                    Stop();
                }

            }
            else
            {
                Start();
            }
        }

        private void Start()
        {
            if (_settings == null || _currentGame == null) return;

            _currentGame.SetAutoGameWindowNormal(); //设置窗体正常化
            Thread.Sleep(100);
            _currentGame.SetAutoGameForeground(); //窗体前置
            Thread.Sleep(100);
            _currentGame.SetAutoGameFocus(); //聚焦窗体
            Thread.Sleep(100);
            _currentGame.SetGameBounds(_settings.DefaultResolutionRatioSize); //设置窗体大小

            _sceneMatchEngine.SetCurrentGame(_currentGame);
            _processMatchEngine.SetCurrentGame(_currentGame);
            _languageScriptEngine.SetCurrentGame(_currentGame);
            _kmActionEngine.SetCurrentGame(_currentGame);

            _sceneMatchEngine.Start();

            _languageScriptEngine.Start();
            _kmActionEngine.Start();

            if (_licence?.UseGameProcess == 0)
            {
                WriteLog("当前卡密没有游戏过程数据识别权限,请升级卡密.");
            }
            else
            {
                _processMatchEngine.Start();
            }
            _captureHelper = new CaptureHelper();
            _captureHelper.Fps = _settings.CaptureFrameRate;
            _captureHelper.CaptureDone += OnCaptureDone;
            _captureHelper?.Start(Guid.NewGuid().ToString(), _currentGame.Handle, CaptureType.PrintWindow);
            _isRunning = true;
            this.tsbtnStart.Text = "停止自动运行";
            //this.tsbtnStart.Image = Properties.Resources.停止;

            WriteLog("游戏自动运行功能已启动.");
        }

        public void Stop()
        {
            _captureHelper?.Stop();
            _captureHelper = null;

            if (_settings == null || _currentGame == null) return;

            //将游戏设置为不顶置
            _currentGame.SetGameBounds(_settings.DefaultResolutionRatioSize, false);

            _sceneMatchEngine.Stop();
            _processMatchEngine.Stop();
            _kmActionEngine.Stop();
            _languageScriptEngine.Stop();

            _isRunning = false;
            this.tsbtnStart.Text = "启动自动运行";
            //this.tsbtnStart.Image = Properties.Resources.启动;
            WriteLog("已停止运行.");
        }

        private void OnHookEvent(HookEventArgs e)
        {
            if (_currentGame != null && (e.RawEvent.Mask == SharpHook.Native.ModifierMask.LeftCtrl || e.RawEvent.Mask == SharpHook.Native.ModifierMask.RightCtrl) && e.RawEvent.Keyboard.KeyCode == SharpHook.Native.KeyCode.VcP)
            {
                try
                {
                    _hookStartGame = true;
                    Invoke((new Action(() =>
                    {
                        tsbtnStart_Click(this, EventArgs.Empty);
                    })));
                }
                catch (Exception)
                {
                }
                finally
                {
                    _hookStartGame = false;
                }
            }
        }
    }
}
